﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Media3D;
using System.Windows.Threading;
using Wen.Core;

namespace Wen.UI
{
	/// <summary>
	/// Interaction logic for NavigationWindow.xaml
	/// </summary>
	public partial class NavigationWindow : Window
	{
		public static NavigationWindow Instance { get; set; }

		public NavigationWindow() {
			Application.Current.Resources.MergedDictionaries.Add(NavigatorHelpers.LoadResourceDictionary("/Wen;component/Resources/Images/Images.xaml"));
			Application.Current.Resources.MergedDictionaries.Add(NavigatorHelpers.LoadResourceDictionary("/Wen;component/Resources/Style/Border.xaml"));
			Application.Current.Resources.MergedDictionaries.Add(NavigatorHelpers.LoadResourceDictionary("/Wen;component/Resources/Style/Button.xaml"));
			Application.Current.Resources.MergedDictionaries.Add(NavigatorHelpers.LoadResourceDictionary("/Wen;component/Resources/Style/HeaderedContentControl.xaml"));
			Application.Current.Resources.MergedDictionaries.Add(NavigatorHelpers.LoadResourceDictionary("/Wen;component/Resources/Style/ItemsControl.xaml"));
			Application.Current.Resources.MergedDictionaries.Add(NavigatorHelpers.LoadResourceDictionary("/Wen;component/Resources/Style/TabControl.xaml"));
			Application.Current.Resources.MergedDictionaries.Add(NavigatorHelpers.LoadResourceDictionary("/Wen;component/Resources/Style/Expander.xaml"));
			Application.Current.Resources.MergedDictionaries.Add(NavigatorHelpers.LoadResourceDictionary("/Wen;component/Resources/Style/HeaderedContentControl.xaml"));
			Application.Current.Resources.MergedDictionaries.Add(NavigatorHelpers.LoadResourceDictionary("/Wen;component/Resources/Resources.xaml"));
			InitializeComponent();
			DataContext = new NavigationViewModel(null);
			Instance = this;
			RecoverPosition();
		}

		public static void Go() {
			AppDomain.CurrentDomain.AssemblyResolve += CurrentDomainAssemblyResolve;
			ShowNavigator();
		}

		public static void ShowNavigator(Viewport3D viewport3D) {
			if (viewport3D != null) {
				if (viewport3D.Camera == null) {
					CrashInitNavigation("Camera must be non-null.");
					return;
				}
				ProjectionCamera projectionCamera = viewport3D.Camera as ProjectionCamera;
				if (projectionCamera == null) {
					CrashInitNavigation("Camera must be a ProjectionCamera");
					return;
				}
				if (projectionCamera.Transform == Transform3D.Identity) {
					projectionCamera.Transform = new MatrixTransform3D();
				}
			}
			NavigationViewModel navigationViewModel = new NavigationViewModel(viewport3D);
			NavigationWindow navigationWindow = new NavigationWindow() { DataContext = navigationViewModel };
			navigationWindow.Show();
		}

		private static void ShowNavigator() {
			Dispatcher dispatcher = Application.Current == null ? Dispatcher.CurrentDispatcher : Application.Current.Dispatcher;

			if (dispatcher.CheckAccess()) {
				List<Viewport3D> viewport3Ds = Application.Current.MainWindow.FindVisualChild<Viewport3D>(null).ToList();
				if (viewport3Ds.Count > 0)
					ShowNavigator(viewport3Ds[0]);
				else {
					CrashInitNavigation("This application does not contain a viewport");
				}
			}
			else {
				dispatcher.Invoke((Action)ShowNavigator);
			}
		}

		private static void CrashInitNavigation(string error) {
			MessageBox.Show(error);
			ShowNavigator(null);
		}

		private static readonly string[] ResolvableAssemblies = new[] { "Wen.Core", "IconLib", "System.Windows.Interactivity" };
		static Assembly CurrentDomainAssemblyResolve(object sender, ResolveEventArgs args) {
			string directory = Path.GetDirectoryName(typeof(NavigationWindow).Assembly.Location);
			string assemblyName = args.Name.Split(',')[0];
			if (ResolvableAssemblies.Any(assemblyName.Contains))
				return Assembly.LoadFile(Path.Combine(directory, assemblyName) + ".dll");
			return null;
		}

		public void CloseWindow() {
			if (Application.Current.MainWindow == this)
				Application.Current.Shutdown();
			else
				Close();
		}

		private void NavigatorWindowClosing(object sender, System.ComponentModel.CancelEventArgs e) {
			SavePosition();
		}

		#region Positioning

		private void RecoverPosition() {
			Left = Properties.Settings.Default.WindowLeft;
			Top = Properties.Settings.Default.WindowTop;
		}

		private void SavePosition() {
			Properties.Settings.Default.WindowLeft = Left;
			Properties.Settings.Default.WindowTop = Top;
			Properties.Settings.Default.Save();
		}

		#endregion
	}
}
